package top.maof.book.aspect;

import io.swagger.annotations.ApiModel;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import top.maof.book.annotation.Cache;

import java.lang.reflect.Method;


/**
 * CacheAspect 和 Cache注解配合使用
 * 注意: 当使用了@Cache,SpringBoot的其他注解可能无法生效
 * <p>
 * 已弃用,兼容性差,功能太弱,远不如SpringBoot自带的注解
 * 使用时会导致部分Aspect无法生效
 */
@ApiModel("热点数据缓存")
// @Aspect
// @Component
@Slf4j
@Deprecated
public class CacheAspect {

    @Autowired
    ValueOperations<String, Object> valueOperations;


    @Pointcut("@annotation(top.maof.book.annotation.Cache)")
    public void cache() {

    }


    /**
     * 缓存处理
     */
    @Around("cache()")
    public Object handleControllerMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("CacheAspect 执行...");


        //获取连接点的方法签名对象
        Signature signature = joinPoint.getSignature();

        //获取方法
        Method method = ((MethodSignature) signature).getMethod();

        // 获取注解
        Cache cache = method.getAnnotation(Cache.class);


        Class returnType = ((MethodSignature) signature).getReturnType();

        // 定义返回值
        Object returnObj = null;


        // 解析缓存key

        // 创建解析器
        SpelExpressionParser parser = new SpelExpressionParser();
        // 获取表达式
        Expression expression = parser.parseExpression(cache.name());
        // 设置解析上下文(有哪些占位符，以及每种占位符的值)
        EvaluationContext context = new StandardEvaluationContext();
        //获取参数值
        Object[] args = joinPoint.getArgs();
        //获取运行时参数的名称
        DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
        String[] parameterNames = discoverer.getParameterNames(method);

        for (int i = 0; i < parameterNames.length; i++) {
            context.setVariable(parameterNames[i], args[i]);
        }
        //解析,获取替换后的结果
        // 最终的key为缓存空间名+缓存名
        String key = cache.ex() + ":" + expression.getValue(context).toString();


        if (cache != null) {
            switch (cache.type()) {
                // 查找
                case SELECT:
                    // 缓存不为空,直接返回
                    returnObj = valueOperations.get(key);
                    if (returnObj != null) {
                        return returnObj;
                    }
                    // 缓存为空,获取方法返回值,设置进缓存
                    returnObj = joinPoint.proceed();
                    valueOperations.set(key, returnObj, cache.expire(), cache.unit());
                    break;
                // 删除
                case DELETE:
                    // 移除缓存
                    valueOperations.getOperations().delete(key);
                    returnObj = joinPoint.proceed();
                    break;
            }
        }


        return returnObj;
    }
}
